home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Tool Chest / Development Tools & Languages / Dylan Related / Mindy / Mindy 1.2 - portable sources / libraries / coll-ext / heap.dylan next >
Encoding:
Text File  |  1995-03-15  |  17.5 KB  |  557 lines  |  [TEXT/ttxt]

  1. module:     heap
  2. rcs-header:    $Header: heap.dylan,v 1.3 94/11/03 23:39:25 wlott Exp $
  3. author:     Nick Kramer (nkramer@cs.cmu.edu)
  4. synopsis:    Provides <heap>, a popular data structure for priority queues.
  5.         The semantics are basically those of a sorted sequence, with
  6.         particularly efficient implementations of add!, first, and pop
  7.         (i.e.  "remove-first").
  8.  
  9. //======================================================================
  10. //
  11. // Copyright (c) 1994  Carnegie Mellon University
  12. // All rights reserved.
  13. // 
  14. // Use and copying of this software and preparation of derivative
  15. // works based on this software are permitted, including commercial
  16. // use, provided that the following conditions are observed:
  17. // 
  18. // 1. This copyright notice must be retained in full on any copies
  19. //    and on appropriate parts of any derivative works.
  20. // 2. Documentation (paper or online) accompanying any system that
  21. //    incorporates this software, or any part of it, must acknowledge
  22. //    the contribution of the Gwydion Project at Carnegie Mellon
  23. //    University.
  24. // 
  25. // This software is made available "as is".  Neither the authors nor
  26. // Carnegie Mellon University make any warranty about the software,
  27. // its performance, or its conformity to any specification.
  28. // 
  29. // Bug reports, questions, comments, and suggestions should be sent by
  30. // E-mail to the Internet address "gwydion-bugs@cs.cmu.edu".
  31. //
  32. //======================================================================
  33.  
  34. //============================================================================
  35. // A heap is an implementation of the abstract data type "sorted list". A heap
  36. // is a sorted sequence of items.  Most likely the user will end up writing
  37. // something like 
  38. // 
  39. // define class <heap-item> (<object>);
  40. //   slot priority;
  41. //   slot data;
  42. // end class <heap-item>;
  43. // 
  44. // with appropriate methods defined for < and =. The user could, however, have
  45. // simply a sorted list of integers, or have some item where the priority is
  46. // an integral part of the item itself.  
  47. // 
  48. // make on heaps supports the less-than: keyword, which supply the heap's
  49. // comparison and defaults to <.  
  50. // 
  51. // Heaps support all the usual sequence operations. The most useful ones:  
  52. // 
  53. //      push(heap, item) => updated-heap
  54. //      pop(heap)        => smallest-element
  55. //      first(heap)      => smallest-element
  56. //      second(heap)     => second-smallest-element
  57. //      add!(heap, item) => updated-heap
  58. //      sort, sort!      => sorted-sequence
  59. // 
  60. // These are all "efficient" operations (defined below).  As with <deque>,
  61. // push is another name for add!, and does exactly the same thing except that
  62. // push doesn't accept any keywords.  sort and sort! return a sequence that's
  63. // not a heap. Not necessarily efficient but useful anyhow:  
  64. // 
  65. //      add-new!(heap, item, #key test:, efficient:) => updated-heap
  66. //      remove!(heap, item, #key test:, efficient:) => updated-heap
  67. //      member?(heap, item, #key test:, efficient:) => <boolean>
  68. // 
  69. // The efficient: keyword defaults to #f. If #t, it uses the
  70. // random-iteration-protocol (which is considerably more efficient, but isn't
  71. // really standard behavior, so it had to be optional).  Conceivably most
  72. // sequence methods could support such a keyword, but they don't yet.  
  73. // 
  74. // The user can use element-setter or the iteration protocol to change an item
  75. // in the heap, but changing the priority of an item is an error and Bad
  76. // Things(tm) will happen. No error will be signaled.  Both of these
  77. // operations are very inefficient.  
  78. // 
  79. // Heaps are NOT <stretchy-collection>s, although add! and pop can magically
  80. // change the size of the heap.  
  81. // 
  82. // Efficiency: Approximate running times of different operations are given
  83. // below: (N is the size of the heap) 
  84. // 
  85. //     first, first-setter                             O(1)
  86. //     second (but not second-setter)                  O(1)
  87. //     size                                            O(1)
  88. //     add!                                            O(lg N)
  89. //     push                                            O(lg N)
  90. //     pop(heap)                                       O(lg N)
  91. //     sort, sort!                                     O(N * lg N)
  92. //     forward-iteration-protocol          
  93. //                             setup:                  O(N)
  94. //                             next-state:             O(lg N)
  95. //                             current-element:        O(1)
  96. //                             current-element-setter: O(N)
  97. //     backwards-iteration-protocol
  98. //                             setup:                  O(N * lg N)
  99. //                             next-state:             O(1)
  100. //                             current-element:        O(1)
  101. //                             current-element-setter: O(N)
  102. //     random-iteration-protocol           
  103. //                             setup:                  O(1)
  104. //                             next-state:             O(1)
  105. //                             current-element:        O(1)
  106. //                             current-element-setter: O(1)
  107. //     element(heap, M)                                O(M*lg N + N)
  108. //     element-setter(value, heap, M)                  O(N + M*lg N + M)
  109. // 
  110. // element, element-setter on arbitrary keys use the
  111. // forward-iteration-protocol (via the inherited methods), and have
  112. // accordingly bad performance.  
  113. //============================================================================
  114.  
  115.  
  116. define class <heap> (<mutable-sequence>)
  117.   slot heap-size      :: <fixed-integer>;
  118.   slot heap-data      :: <stretchy-vector>;
  119.   slot heap-less-than :: <function>;
  120. end class <heap>;
  121.  
  122.  
  123. // The size: keyword is accepted but ignored
  124. //
  125. define method initialize (h :: <heap>, #next next-method,
  126.               #key size: size,
  127.               less-than: less-than = \<)
  128.   h.heap-size      := 0;
  129.   h.heap-data      := make(<stretchy-vector>);
  130.   h.heap-less-than := less-than;
  131.   next-method();
  132. end method initialize;
  133.  
  134.  
  135. define method class-for-copy(h :: <heap>);
  136.   <stretchy-vector>;
  137. end method class-for-copy;
  138.  
  139.  
  140. define method shallow-copy(old-heap :: <heap>) => new-heap :: <heap>;
  141.   let new-heap = make(<heap>);
  142.   new-heap.heap-size := old-heap.heap-size;
  143.   new-heap.heap-data := shallow-copy(old-heap.heap-data);
  144.   new-heap.heap-less-than := old-heap.heap-less-than;
  145.   new-heap;
  146. end method shallow-copy;
  147.  
  148.  
  149. define method as(cls == <heap>, coll :: <collection>)
  150.     => (result :: <heap>);
  151.   let heap = make(<heap>);
  152.   for (elem in coll)
  153.     add!(heap, elem);
  154.   end for;
  155.   heap;
  156. end method as;
  157.  
  158.  
  159. define method size (h :: <heap>) => size :: <fixed-integer>;
  160.   h.heap-size;
  161. end method size;
  162.  
  163.  
  164. define method empty? (h :: <heap>);
  165.   h.heap-size = 0;
  166. end method empty?;
  167.  
  168.  
  169. define constant no-default = "no-default";
  170.  
  171. // Inherit inefficient method for element.
  172.  
  173. // Special case the top, which can be done efficiently because we
  174. // don't have to call the iteration protocol.
  175. //
  176. define method element(h :: <heap>, index == 0,
  177.               #key default = no-default) => elt :: <object>;
  178.   if (empty?(h))
  179.     if (default == no-default)
  180.       error("No such element");
  181.     else 
  182.       default;
  183.     end if;
  184.   else
  185.     h.heap-data[0];
  186.   end if;
  187. end method element;  
  188.  
  189.  
  190. // Special case the second as well because it can be done
  191. // semi-efficiently (again, no iteration protocol)
  192. //
  193. define method element(h :: <heap>, index == 1,
  194.               #key default = no-default) => elt :: <object>;
  195.   if (size(h) < 2)
  196.     if (default == no-default)
  197.       error("No such element");
  198.     else 
  199.       default;
  200.     end if;
  201.   else
  202.     h.heap-data[smaller-child(h, 0)];
  203.   end if;
  204. end method element;  
  205.  
  206.  
  207. // Inherit inefficient element-setter
  208.  
  209. // Special case the top, which can be done efficiently and without the
  210. // iteration protocol
  211. //
  212. define method element-setter(value, h :: <heap>, index == 0);
  213.   h.heap-data[0] := value;
  214.   value;
  215. end method element-setter;
  216.  
  217.  
  218. // element-setter uses element to figure out which element is the
  219. // key'th biggest, and then traverses the internal data structure
  220. // (through a call to find-index) to find that element in order to
  221. // change it.
  222. //
  223. define method element-setter(new-elt, h :: <heap>, key :: <fixed-integer>);
  224.   h.heap-data [find-index(h, h[key])] := new-elt;
  225. end method element-setter;
  226.  
  227.  
  228. define method add! (h :: <heap>, new-elt) => changed-heap :: <heap>;
  229.   h.heap-data [h.heap-size] := new-elt;
  230.   h.heap-size := 1 + h.heap-size;
  231.   upheap(h, h.heap-size - 1);
  232.   h;
  233. end method add!;
  234.  
  235.  
  236. define method add-new!(h :: <heap>, new-elt, 
  237.                #key test: test = \=, efficient: efficient = #f)
  238.     => changed-heap :: <heap>;
  239.   if (~ member?(h, new-elt, test: test, efficient: efficient))
  240.     add!(h, new-elt);
  241.   else 
  242.     h;
  243.   end if;
  244. end method add-new!;  
  245.  
  246.  
  247. define method push(h :: <heap>, new-elt)  =>  changed-heap :: <heap>;
  248.   add!(h, new-elt);
  249. end method push;
  250.  
  251.  
  252. define method pop (h :: <heap>) => smallest-item;
  253.   let smallest-item = h.heap-data [0];
  254.   h.heap-data [0] := h.heap-data [size(h) - 1];
  255. //  remove!(h.heap-data, size(h) - 1);    // Adjust stretchy vector
  256.   h.heap-size := h.heap-size - 1;
  257.   downheap(h, 0);
  258.   smallest-item;
  259. end method pop;
  260.  
  261.  
  262. // This is rather complicated because it can use two different
  263. // iteration protocols and has to be able to remove an arbitrary
  264. // number of items from the heap. Further complicating it, removing an
  265. // element from the heap disturbs it, so you have to FIND the
  266. // elements to remove, THEN remove them.
  267. //
  268. define method remove!(h :: <heap>, elt,
  269.               #key test: test = \=, efficient: efficient = #f)
  270.     => changed-heap :: <heap>;
  271.   let (init, limit, next, finished?, cur-key, cur-elt) =
  272.     if (efficient)     random-iteration-protocol(h);
  273.     else            forward-iteration-protocol(h);
  274.     end if;
  275.  
  276.   let kill-list = #();
  277.  
  278.   for (state = init then next(h, state), until finished?(h, state, limit))
  279.     if (test(elt, cur-elt(h, state)))
  280.       kill-list := add!(kill-list, cur-elt(h, state));
  281.     end if;
  282.   end for;
  283.  
  284.   for (dead-elt in kill-list)
  285.     let index = find-index(h, dead-elt);
  286.     let old-item = h.heap-data[index];
  287.     h.heap-size := h.heap-size - 1;
  288.     h.heap-data[index] := h.heap-data[h.heap-size];
  289.     let new-item = h.heap-data[index];
  290.  
  291.     if (h.heap-less-than(old-item, new-item))
  292.       upheap(h, index);
  293.     elseif (h.heap-less-than(new-item, old-item))
  294.       downheap(h, index);
  295.     end if;
  296.   end for;
  297.     
  298.   h;
  299. end method remove!;
  300.  
  301.  
  302. define method member?(h :: <heap>, elt, #key test: test = \=,
  303.               efficient: efficient = #f);
  304.   let (init, limit, next, finished?, cur-key, cur-elt) =
  305.     if (efficient)     random-iteration-protocol(h);
  306.     else            forward-iteration-protocol(h);
  307.     end if;
  308.  
  309.   block (return)
  310.     for (state = init then next(h, state), until finished?(h, state, limit))
  311.       if (test(elt, cur-elt(h, state)))
  312.     return(#t);
  313.       end if;
  314.     end for;
  315.     #f;
  316.   end block;
  317. end method member?;
  318.  
  319.  
  320. // Can't use backwards-iteration-protocol because that uses reverse
  321. //
  322. define method reverse(h :: <heap>);
  323.   let new-seq = make(class-for-copy(h), size: size(h));
  324.   for (elt in h, index = size(h) - 1  then index - 1)
  325.     new-seq[index] := elt;
  326.   end for;
  327.   new-seq;
  328. end method reverse;
  329.  
  330.  
  331. define method reverse!(h :: <heap>);
  332.   reverse(h);
  333. end method reverse!;
  334.  
  335.  
  336. define method sort(h :: <heap>, #next next-method,
  337.            #key test: test = \<, stable: stable = #f);
  338.   if (test == h.heap-less-than)
  339.     let new-seq = make(class-for-copy(h), size: size(h));
  340.     for (elt in h, index = 0 then index + 1)
  341.       new-seq[index] := elt;
  342.     end for;
  343.     new-seq;
  344.   else
  345.     sort(h.heap-data, test: test, stable: stable);
  346.   end if;
  347. end method sort;
  348.  
  349.  
  350. define method sort!(h :: <heap>, #rest key-value-pairs, #key);
  351.   apply(sort, h, key-value-pairs);
  352. end method sort!;
  353.  
  354. /* ---------------------------------------------------------------------*/
  355. // Internal functions
  356. /* ---------------------------------------------------------------------*/
  357.  
  358. // All internal operations specify things by their index into the vector.
  359.  
  360. define method parent (index :: <fixed-integer>) => parent-index :: <integer>;
  361.   floor/(index - 1, 2);
  362. end method parent;
  363.  
  364.  
  365. define method left-child (index :: <fixed-integer>)
  366.     => left-child-index :: <fixed-integer>;
  367.   2 * index + 1;
  368. end method left-child;
  369.  
  370.  
  371. define method right-child (index :: <fixed-integer>)
  372.     => right-child-index :: <fixed-integer>;
  373.   2 * index + 2;
  374. end method right-child;
  375.  
  376.  
  377. // Assumes the left child is valid, although the right child might not be.
  378. //
  379. define method smaller-child (h :: <heap>, index :: <fixed-integer>)
  380.     => smaller-child-index :: <fixed-integer>; 
  381.   if (right-child(index) = size(h))
  382.     left-child(index);            // There is no right child
  383.   elseif (h.heap-less-than(h.heap-data [right-child(index)],
  384.                h.heap-data [left-child(index)]))
  385.     right-child(index);
  386.   else
  387.     left-child(index);
  388.   end if;
  389. end method;
  390.  
  391.  
  392. // Move a small item up
  393. //
  394. define method upheap (h :: <heap>, index :: <fixed-integer>);
  395.   let item = h.heap-data [index];
  396.  
  397.   while (index ~= 0   &   
  398.        h.heap-less-than (item, h.heap-data [parent(index)]))
  399.     h.heap-data [index] := h.heap-data [parent(index)];
  400.     index := parent(index);
  401.   end while;
  402.   h.heap-data [index] := item;
  403. end method upheap;
  404.  
  405.  
  406. // Move a big item down
  407. //
  408. define method downheap (h :: <heap>, index :: <fixed-integer>);
  409.   let item = h.heap-data [index];
  410.  
  411.   while ( left-child(index) < size(h)
  412.        & h.heap-less-than(h.heap-data [smaller-child(h,index)], item))
  413.     h.heap-data [index] := h.heap-data [smaller-child(h,index)];
  414.     index := smaller-child(h,index);
  415.   end while;
  416.  
  417.   h.heap-data [index] := item;
  418. end method downheap;
  419.  
  420.  
  421. define method find-index(h :: <heap>, elt) => index :: <fixed-integer>;
  422.   let index = 0;
  423.   until (h.heap-data[index] == elt)
  424.     index := index + 1;
  425.   end until;
  426.   index;
  427. end method find-index;
  428.  
  429. /* ---------------------------------------------------------------------*/
  430. // Iteration protocols
  431. /* ---------------------------------------------------------------------*/
  432.  
  433. // Not very efficient. Each next-state operation costs lg n (where n
  434. // is the size of the heap), and it presumably costs N to set up.
  435. //
  436. define method forward-iteration-protocol (coll :: <heap>);
  437.   values(shallow-copy(coll),          // initial-state
  438.      #f,                          // limit (not used)
  439.                                   // next-state
  440.      method(h :: <heap>, state :: <heap>) => new-state :: <heap>;
  441.          pop(state);
  442.          state;
  443.      end method,
  444.  
  445.                                   // finished-state?
  446.      method(h :: <heap>, state :: <heap>, limit);
  447.          empty?(state);
  448.      end method,
  449.  
  450.                                   // current-key
  451.      method(h :: <heap>, state :: <heap>) => key :: <fixed-integer>;
  452.          h.heap-size - state.heap-size;
  453.      end method,
  454.  
  455.                                   // current-element
  456.      method(h :: <heap>, state :: <heap>)
  457.          first(state);
  458.      end method,
  459.  
  460.                                   // current-element-setter
  461.      method(value, h :: <heap>, state :: <heap>)
  462.          let index = find-index(h, first(state));
  463.          h.heap-data[index] := value;
  464.          state.heap-data[0] := value;
  465.      end method,
  466.  
  467.                                   // copy-state
  468.      method(h :: <heap>, state :: <heap>) => new-state :: <heap>;
  469.          shallow-copy(state);
  470.      end method);
  471. end method forward-iteration-protocol;
  472.  
  473.  
  474. // Not very efficient. Calling backwards-iteration-protocol takes n lg n 
  475. // time, after which each access is constant time (except for
  476. // current-element-setter, which is m lg n where m is the index of the
  477. // element that's being changed).
  478. //
  479. define method backwards-iteration-protocol (coll :: <heap>);
  480.   let sorted-vector = reverse(coll);
  481.  
  482.   values(coll.heap-size - 1,          // initial-state
  483.      -1,                          // limit
  484.                                   // next-state
  485.      method(h :: <heap>, state :: <fixed-integer>) => new-state :: <integer>;
  486.          state - 1;
  487.      end method,
  488.  
  489.                                   // finished-state?
  490.      method(h :: <heap>, state :: <fixed-integer>, limit :: <integer>);
  491.          state = limit;
  492.      end method,
  493.  
  494.                                   // current-key
  495.      method(h :: <heap>, state :: <fixed-integer>) => key :: <integer>;
  496.          state;
  497.      end method,
  498.  
  499.                                   // current-element
  500.      method(h :: <heap>, state :: <fixed-integer>)
  501.          sorted-vector[state];
  502.      end method,
  503.  
  504.                                   // current-element-setter
  505.      method(value, h :: <heap>, state :: <fixed-integer>)
  506.          let index = find-index(h, sorted-vector[state]);
  507.          h.heap-data[index] := value;
  508.           sorted-vector[state] := value;
  509.      end method,
  510.  
  511.                                   // copy-state
  512.      method(h :: <heap>, state :: <fixed-integer>) => new-state :: <integer>;
  513.          state;
  514.      end method);
  515. end method backwards-iteration-protocol;
  516.  
  517.  
  518. // Just plows through the heap in the order things appear in the vector.
  519. // Constant time access. Doesn't implement current-key.
  520. //
  521. define method random-iteration-protocol (collection :: <heap>);
  522.   values(0,                      // initial-state
  523.      size(collection),                // limit
  524.  
  525.                              // next-state
  526.      method (h :: <heap>, state :: <fixed-integer>) => next-state :: <integer>;
  527.        state + 1;
  528.      end method,
  529.      
  530.                              // finished-state?
  531.      method (h :: <heap>, state :: <fixed-integer>, limit :: <integer>);
  532.        state = limit;
  533.      end method,
  534.  
  535.                              // current-key
  536.      method (h :: <heap>, state :: <fixed-integer>) => key :: <integer>;
  537.        error("I have no idea what the current-key is.");
  538.      end method,
  539.  
  540.                              // current-element
  541.      method (h :: <heap>, state :: <fixed-integer>);
  542.        h.heap-data [state];
  543.      end method,
  544.  
  545.                              // current-element-setter
  546.      method (value, h :: <heap>, state :: <fixed-integer>);
  547.        h.heap-data[state] := value;
  548.      end method,
  549.  
  550.                              // copy-state
  551.      method (h :: <heap>, state :: <fixed-integer>) => state :: <integer>;
  552.        state;
  553.      end method
  554.     );
  555. end method random-iteration-protocol;     
  556.  
  557.